package com.yungu.swift.order.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.yungu.swift.assets.driver.model.dto.DriverCashDto;
import com.yungu.swift.assets.driver.model.dto.DriverDto;
import com.yungu.swift.assets.driver.service.DriverCashService;
import com.yungu.swift.assets.driver.service.DriverService;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.constants.FinanceConstant;
import com.yungu.swift.order.service.WxPayCashService;
import com.yungu.swift.order.utils.PaySignBuilder;
import com.yungu.swift.order.utils.TenpayHttpClient;
import com.yungu.swift.order.utils.WxToBankBuilder;
import com.yungu.swift.order.utils.XmlUtils;
import com.yungu.swift.system.finance.model.dto.FinanceWithdrawalDto;
import com.yungu.swift.system.finance.service.FinanceWithdrawalService;
import com.yungu.swift.system.sys.model.dto.SysAccountPlatformDto;
import com.yungu.swift.system.sys.service.SysAccountPlatformService;
import com.yungu.swift.utils.DateUtils;
import com.yungu.swift.utils.MapUtils;
import com.yungu.swift.utils.Md5Utils;
import com.yungu.swift.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import static com.yungu.swift.order.config.NacosListener.WXPAY_CONFIG;

/**
 * @Author xiuyin.cui
 * @Date 2020-05-18 10:08
 * @Description 微信提现转账实现
 */
@Slf4j
@Service
public class WxPayCashServiceImpl implements WxPayCashService {

    @Reference
    private DriverService driverService;
    @Reference
    private DriverCashService driverCashService;
    @Reference
    private FinanceWithdrawalService financeWithdrawalService;
    @Reference
    private SysAccountPlatformService sysAccountPlatformService;

    private static final String WX_TO_ACCOUNT = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";

    @Override
    public ResponseData<Map<String, String>> toAccount(String name, String account, double amount, String serialNum) {
        log.error("788888888888");
        log.error(name,account,serialNum);
        int actualAmount = BigDecimal.valueOf(amount * 100).intValue();
        DriverDto driverDto = driverService.get(MapUtils.build("mobile", account)).getData();
        log.error("22222222");
        log.error(driverDto.getOpenId(),driverDto);
        log.error(String.valueOf(driverDto));
        if (driverDto == null) {
            log.info("mobile：{} can't find driverdto，toAccount fail", account);
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到账户信息，转账失败");
        }
        DriverCashDto driverCashDto = driverCashService.get(MapUtils.build("serialNum", serialNum)).getData();
        if (driverCashDto == null) {
            log.warn("serialNum：{} can't find driverCashDto. ", serialNum);
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到提现信息，转账失败");
        }
        SysAccountPlatformDto accountPlatformDto = sysAccountPlatformService.getByAppid(driverCashDto.getAppid()).getData();
        //获取平台信息
        if (accountPlatformDto == null) {
            log.warn("appid：{} can't find SysAccountPlatformDto. ", driverCashDto.getAppid());
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到平台信息");
        }
        log.error("6666666");
        boolean success = true;
        String msg = "";
        Map<String, String> resultMap = toAccountImpl(name, actualAmount, serialNum, driverDto.getOpenId());
        log.error("99999999999999999");
        log.error("打印查看微信返回的信息：{}",resultMap);
        if (resultMap == null || resultMap.isEmpty()) {
            success = false;
            msg = "微信系统无响应";
            log.error("微信转账个人账户:{} XML解析异常，流水号：{}", account, serialNum);
        }
        if (!"SUCCESS".equals(resultMap.get("return_code"))) {
            success = false;
            msg = resultMap.get("return_msg");
            log.error("微信转账个人账户:{} 通讯异常：{}，流水号：{}", account, msg, serialNum);
        }
        // 出现未明确的错误码时（SYSTEMERROR等），请务必用原商户订单号重试
        if ("SYSTEMERROR".equals(resultMap.get("err_code"))) {
            log.info("wx to account:{} error：{}. retry", account, resultMap.get("err_code_des"));
            resultMap = toAccountImpl(name, actualAmount, serialNum, driverDto.getOpenId());
            if (resultMap == null || resultMap.isEmpty()) {
                success = false;
                msg = "微信系统无响应";
                log.error("微信转账个人账户重试:{} XML解析异常，流水号：{}", account, serialNum);
            }
            if (!"SUCCESS".equals(resultMap.get("return_code"))) {
                success = false;
                msg = resultMap.get("return_msg");
                log.error("微信转账个人账户:{} 通讯异常：{}，流水号：{}", account, msg, serialNum);
            }
        }
        if (!"SUCCESS".equals(resultMap.get("result_code"))) {
            success = false;
            msg = resultMap.get("err_code_des");
            log.error("微信转账个人账户:{} 通讯异常：{}，流水号：{}", account, msg, serialNum);
        }
        // 记录转账流水
        recordFlow(success, msg, resultMap, driverCashDto, accountPlatformDto);
        return ResponseData.buildSuccessResponse(resultMap);
    }

    private void recordFlow(boolean success, String msg, Map<String, String> resultMap, DriverCashDto driverCashDto, SysAccountPlatformDto accountPlatformDto) {
        log.info("流水号：{} 提现：{}，开始记录提现流水", driverCashDto.getSerialNum(), success ? "成功" : "失败");
        if (success) {
            String paymentTime = resultMap.get("payment_time");
            //打款成功时间
            driverCashDto.setWithdrawalFinishTime(DateUtils.parse(paymentTime));
            //获取转账手续费 单位为分 转换成元
            driverCashDto.setThirdPoundage(0.0);
            //记录平台流水提现和提现手续费记录
            //获取平台初始余额
            BigDecimal cashBalance = accountPlatformDto.getCashBalance();

            //提现金额
            BigDecimal amount = BigDecimal.valueOf(driverCashDto.getActualAmount());
            //保存平台提现到支付宝的流水记录
            FinanceWithdrawalDto financeWithdrawal = new FinanceWithdrawalDto();
            financeWithdrawal.setUuid(StringUtils.buildUUID());
            financeWithdrawal.setFinanceNumber(StringUtils.buildUUID());
            financeWithdrawal.setHappenTime(new Date());
            financeWithdrawal.setAmount(amount);
            financeWithdrawal.setBusinessUuid(driverCashDto.getUuid());
            financeWithdrawal.setFinanceOutflow(accountPlatformDto.getUuid());
            financeWithdrawal.setFinanceInflow("");
            financeWithdrawal.setCourse(FinanceConstant.WITHDRAWAL_TO_ALI);
            financeWithdrawal.setStartBalance(cashBalance);
            cashBalance = cashBalance.subtract(amount);
            financeWithdrawal.setFinalBalance(cashBalance);
            financeWithdrawal.setDescription("平台提现到司机微信账户支付" + amount + "元");
            financeWithdrawal.setCreateOn(new Date());
            financeWithdrawalService.add(financeWithdrawal);

            //保存平台账户
            accountPlatformDto.setCashBalance(cashBalance);
            accountPlatformDto.setUpdateOn(new Date());
            sysAccountPlatformService.edit(accountPlatformDto);

            //设置第三方打款状态为打款成功
            driverCashDto.setThirdPayStatus(DriverCashDto.THIRD_STATUS_SUCCESS);
            //设置提现状态为提现成功
            driverCashDto.setWithdrawalStatus(DriverCashDto.WITHDRAWAL_STATUS_SUCCESS);
            log.info("流水号：{} 提现成功，结束记录提现流水", driverCashDto.getSerialNum());
        } else {
            //修改第三方打款状态为失败
            driverCashDto.setThirdPayStatus(DriverCashDto.THIRD_STATUS_FAILURE);
            //失败原因
            driverCashDto.setThirdReason(msg);
            log.info("流水号：{} 提现失败，失败原因：{}", driverCashDto.getSerialNum(), msg);
        }
        driverCashDto.setUpdateOn(new Date());
        driverCashService.edit(driverCashDto);
        log.info("流水号：{} 记录提现流水结束", driverCashDto.getSerialNum());
    }

    private Map<String, String> toAccountImpl(String name, int amount, String serialNum, String openId) {
        Map<String, String> paramMap = new HashMap<>(16);
        paramMap.put("mch_appid", WXPAY_CONFIG.getDriverWxAppid());
        paramMap.put("mchid", WXPAY_CONFIG.getDriverWxPartner());
        paramMap.put("nonce_str", Md5Utils.encode(String.valueOf(new Random().nextInt(10000))));
        paramMap.put("partner_trade_no", serialNum);
        paramMap.put("openid", openId);
        paramMap.put("check_name", "FORCE_CHECK");
        paramMap.put("re_user_name", name);
        paramMap.put("amount", amount + "");
        paramMap.put("desc", "司机收入提现");
        paramMap.put("sign", PaySignBuilder.wxSignMD5(paramMap, WXPAY_CONFIG.getDriverWxAppKey()));
        String payXml = XmlUtils.buildXml(paramMap);
        Map<String, String> resultMap = new HashMap<>();
        try (InputStream certPath = WxToBankBuilder.class.getResourceAsStream("/apiclient_cert.p12")) {
            String resultStr = TenpayHttpClient.doSslRequest(WX_TO_ACCOUNT, payXml, WXPAY_CONFIG.getDriverWxPartner(), certPath);
            resultMap = XmlUtils.readValueAsMap(resultStr);
        } catch (Exception e) {
            log.error("WxPayCashService toAccount read apiclient_cert.p12 error", e);
        }
        return resultMap;
    }

    @Override
    public ResponseData<Boolean> dataRepair(String uuid) {
        DriverCashDto driverCashDto = driverCashService.get(uuid).getData();
        log.info("流水号：{} 微信提现成功，开始修复提现流水", driverCashDto.getSerialNum());
        ResponseData<SysAccountPlatformDto> responseData = sysAccountPlatformService.getByAppid(driverCashDto.getAppid());
        //获取平台信息
        if (!responseData.isSuccess() || responseData.getData() == null) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "获取不到平台信息");
        }
        SysAccountPlatformDto accountPlatformDto = responseData.getData();
        //打款成功时间
        driverCashDto.setWithdrawalFinishTime(new Date());
        //获取转账手续费 单位为分 转换成元
        driverCashDto.setThirdPoundage(0.0);
        //记录平台流水提现和提现手续费记录
        //获取平台初始余额
        BigDecimal cashBalance = accountPlatformDto.getCashBalance();

        //提现金额
        BigDecimal amount = BigDecimal.valueOf(driverCashDto.getActualAmount());
        //保存平台提现到支付宝的流水记录
        FinanceWithdrawalDto financeWithdrawal = new FinanceWithdrawalDto();
        financeWithdrawal.setUuid(StringUtils.buildUUID());
        financeWithdrawal.setFinanceNumber(StringUtils.buildUUID());
        financeWithdrawal.setHappenTime(new Date());
        financeWithdrawal.setAmount(amount);
        financeWithdrawal.setBusinessUuid(driverCashDto.getUuid());
        financeWithdrawal.setFinanceOutflow(accountPlatformDto.getUuid());
        financeWithdrawal.setFinanceInflow("");
        financeWithdrawal.setCourse(FinanceConstant.WITHDRAWAL_TO_ALI);
        financeWithdrawal.setStartBalance(cashBalance);
        cashBalance = cashBalance.subtract(amount);
        financeWithdrawal.setFinalBalance(cashBalance);
        financeWithdrawal.setDescription("平台提现到司机微信账户支付" + amount + "元");
        financeWithdrawal.setCreateOn(new Date());
        financeWithdrawalService.add(financeWithdrawal);

        //保存平台账户
        accountPlatformDto.setCashBalance(cashBalance);
        accountPlatformDto.setUpdateOn(new Date());
        sysAccountPlatformService.edit(accountPlatformDto);

        //设置第三方打款状态为打款成功
        driverCashDto.setThirdPayStatus(DriverCashDto.THIRD_STATUS_SUCCESS);
        //设置提现状态为提现成功
        driverCashDto.setWithdrawalStatus(DriverCashDto.WITHDRAWAL_STATUS_SUCCESS);
        log.info("流水号：{} 微信提现成功，结束修复提现流水", driverCashDto.getSerialNum());
        driverCashDto.setUpdateOn(new Date());
        return driverCashService.edit(driverCashDto);
    }
}
